home *** CD-ROM | disk | FTP | other *** search
- /* --------------------------------- makemake ----------------------------------
-
- makemake (derived from LFMakeMaker by Laurent Faillie)
-
- SAS/C:
-
- sc main.c
-
- */
-
- /// "compiler"
-
- #ifdef __SASC
-
- #define __USE_SYSBASE
- #define __geta4 __saveds
- #define __stkargs __stdargs
-
- #define __A0 register __a0
- #define __A1 register __a1
- #define __A2 register __a2
- #define __A3 register __a3
- #define __A4 register __a4
- #define __A5 register __a5
- #define __A6 register __a6
- #define __A7 register __a7
- #define __D0 register __d0
- #define __D1 register __d1
- #define __D2 register __d2
- #define __D3 register __d3
- #define __D4 register __d4
- #define __D5 register __d5
- #define __D6 register __d6
- #define __D7 register __d7
-
- #endif
-
- #ifdef _DCC
-
- #define __asm
-
- #endif
-
- ///
- /// "includes"
-
- #include <string.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <ctype.h>
- #include <errno.h>
- #include <unistd.h>
- #include <exec/exec.h>
- #include <dos/dos.h>
- #include <dos/dosextens.h>
- #include <dos/rdargs.h>
- #include <dos/dostags.h>
-
- // prototypes
-
- #include <clib/alib_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/exec_protos.h>
- #include <clib/utility_protos.h>
-
- // pragmas
-
- #ifdef __SASC
-
- #include <pragmas/dos_pragmas.h>
- #include <pragmas/exec_sysbase_pragmas.h>
- #include <pragmas/intuition_pragmas.h>
- #include <pragmas/utility_pragmas.h>
- #include <pragmas/wb_pragmas.h>
-
- #endif
-
- ///
- /// "defines"
-
- #define PATH_MAX 512 // maximum path length
- #define DEFLINE 128 // default line length (in fact DEFLINE + 2)
- #define DEFTAB 8 // width of a TAB character
- #define COMPILE "vc -c -o %obj %src" // command line for creating objects
- #define LINK "vc -o %exe %objs" // command line for creating executable
-
- // flags for makefile generation
-
- #define GENERATE_EXEC (1L<<0)
- #define GENERATE_OBJECT (1L<<1)
- #define GENERATE_FORCE (1L<<2) // do not check ltargets
-
- #ifdef __SASC
-
- UBYTE Version[] = "$VER: makemake 1.0 " __AMIGADATE__ "\n\0";
-
- #else
-
- UBYTE Version[] = "$VER: makemake 1.0 (" __COMMODORE_DATE__ ")\n\0";
-
- #endif
-
- UBYTE About[] = "makemake 1.0 (mail@dietmar-eilert.de)\n";
-
- // command line options
-
- #define TEMPLATE "COMPILE/K,LINK/K,FILES/M/A,IGNORE/K,LOCAL/S,GLOBAL/S,RECURSELOCAL/S,RECURSEGLOBAL/S,EXECUTABLE/K/A,OBJECTS/S,PREFIX/K,INCLUDE/K,SDK/K,CASESENSITIVE/S,NESTEDCOMMENTS/S,MARGIN/N,TABSIZE/N,CONTINUE/S,VERBOSE/S"
-
- enum
- {
- OPTION_COMPILE,
- OPTION_LINK,
- OPTION_FILES,
- OPTION_IGNORE,
- OPTION_LOCAL,
- OPTION_GLOBAL,
- OPTION_RECURSELOCAL,
- OPTION_RECURSEGLOBAL,
- OPTION_EXECUTABLE,
- OPTION_OBJECTS,
- OPTION_PREFIX,
- OPTION_INCLUDE,
- OPTION_SDK,
- OPTION_CASESENSITIVE,
- OPTION_NESTEDCOMMENTS,
- OPTION_MARGIN,
- OPTION_TABSIZE,
- OPTION_CONTINUE,
- OPTION_VERBOSE,
-
- MAX_ARGS
- };
-
- ///
- /// "structures"
-
- /* --------------------------------- ListNode ----------------------------------
-
- All-purpose named-node structure
-
- */
-
- struct ListNode
- {
- struct ListNode *succ;
- char *name;
- };
-
- /* ---------------------------------- Options ----------------------------------
-
- Global processing state
-
- */
-
- struct Options
- {
- const char *compile; // compiler command line for compilation
- const char *link; // compiler command line for compilation and linking
- const char *exec; // executable
- const char *oprefix; // object prefix
- const char *ignore; // ignore pattern
-
- struct ListNode *list_globaldependencies; // list of global dependencies for the current source code
- struct ListNode *list_localdependencies; // list of local dependencies for the current source file
- struct ListNode *list_objects; // list of objects
- struct ListNode *list_targets; // list of targets
- struct ListNode *list_folders; // list of folders where includes reside
-
- BOOL generate_objects; // generate intermediate objects ?
- BOOL local; // consider local includes ?
- BOOL global; // consider global includes ?
- BOOL r_local; // recursively scan local includes ?
- BOOL r_global; // recursively scan global includes ?
-
- BOOL casesensitive; // file names case sensitive ?
- BOOL nestedcomments; // nested comments permitted ?
- BOOL verbose; // verbose ?
- BOOL fatal; // exit on "fatal" errors ?
-
- unsigned int line; // margin
- unsigned int tab; // tab size
-
- char preparsed[PATH_MAX]; // buffer for preparsed pattern
- };
-
- /* ---------------------------------- Status -----------------------------------
-
- Parser status used for parsing source code lines
-
- */
-
- struct Status
- {
- unsigned long line; // line number
- BOOL instring; // we are reading a "" string
- BOOL inconstant; // we are reading a '' string
- unsigned short incomment; // level of nested C comments
- BOOL incommentcpp; // c++ comment
- unsigned short inblock; // level of nested '{ }' blocks
- unsigned char ininclude; // include (9 if '#include' was readed)
- BOOL slash; // last char was a '/'
- BOOL star; // last char was a '*'
- BOOL ignore; // last char was a '\'
- };
-
- ///
- /// "globals"
-
- char cfn[PATH_MAX]; // current file name
- char cpn[PATH_MAX]; // working buffer
-
- extern struct Library *DOSBase;
-
- ///
- /// "prototypes"
-
- extern int AcceptFile (struct Options *options, int local);
- extern void AddGlobal (struct Options *options, struct Status *status, int nr);
- extern void AddLocal (struct Options *options, struct Status *status, int nr);
- extern struct ListNode *AddNode (struct Options *options, struct ListNode **lst, char *x, int end);
- extern void CompletePath (char *path);
- extern struct Parser *CreateParser (char *template);
- extern struct ListNode *FindNode (struct Options *options, struct ListNode **lst, const char *x, struct ListNode **prec );
- extern void FreeList (struct ListNode **lst);
- extern void GenerateTarget (struct Options *options, const char *dst, int flags);
- extern int LocateInclude (struct Options *options, int nr);
- extern int main (int argc, char **argv);
- extern int memicmp (char *stringA, char *stringB, int length);
- extern int Parse (struct Parser *parser, char *buffer, int *position, int *results);
- extern void ReadSource (struct Options *options, const char *x);
- extern char *ReplacePlaceholders(struct Options *options, const char *string, const char *src, const char *exe, const char *obj, const struct ListNode *objs);
- extern char *SkipWS (char *buffer, int *position);
- extern int strcmpopt (const char *y, const char *x, const char **end);
- extern void ValidateFilename (const char *file);
- extern void WriteString (struct Options *options, const char *fch, int smartquote);
-
- ///
- /// "main"
-
- /* -----------------------------------------------------------------------------
-
- main entry point
-
- */
-
- int
- main(int argc, char **argv)
- {
- struct Options *options;
-
- if (options = (struct Options *)malloc(sizeof(struct Options)))
- {
- LONG args[MAX_ARGS];
- struct RDArgs *rdArgs;
-
- // set some defaults
-
- memset(options, 0, sizeof(struct Options));
-
- options->compile = COMPILE;
- options->link = LINK;
- options->line = DEFLINE;
- options->tab = DEFTAB;
- options->fatal = 1;
-
- // read options
-
- memset(args, 0, sizeof(args));
-
- if (rdArgs = ReadArgs(TEMPLATE, args, NULL))
- {
- if (args[OPTION_EXECUTABLE] && args[OPTION_FILES])
- {
- UBYTE **file;
-
- if (args[OPTION_VERBOSE])
- {
- options->verbose = 1;
-
- fputs("makemake ©Dietmar Eilert\n", stderr);
- }
-
- options->exec = (char *)args[OPTION_EXECUTABLE];
-
- ValidateFilename(options->exec);
-
- if (args[OPTION_COMPILE])
-
- options->compile = (char *)args[OPTION_COMPILE];
-
- if (args[OPTION_LINK])
-
- options->link = (char *)args[OPTION_LINK];
-
- if (args[OPTION_LOCAL])
-
- options->local = 1;
-
- if (args[OPTION_GLOBAL])
-
- options->global = 1;
-
- if (args[OPTION_RECURSELOCAL])
-
- options->r_local = 1;
-
- if (args[OPTION_RECURSEGLOBAL])
-
- options->r_global = 1;
-
- if (args[OPTION_PREFIX])
- {
- options->oprefix = (char *)args[OPTION_PREFIX];
-
- ValidateFilename(options->oprefix);
- }
-
- if (args[OPTION_INCLUDE])
- {
- AddNode(options, &options->list_folders, (char *)args[OPTION_INCLUDE], 1);
- }
-
- if (args[OPTION_SDK])
- {
- AddNode(options, &options->list_folders, (char *)args[OPTION_SDK], 1);
- }
-
- if (args[OPTION_CASESENSITIVE])
-
- options->casesensitive = 1;
-
- if (args[OPTION_NESTEDCOMMENTS])
-
- options->nestedcomments = 1;
-
- if (args[OPTION_MARGIN])
-
- options->line = *(LONG *)args[OPTION_MARGIN];
-
- if (args[OPTION_TABSIZE])
-
- options->tab = *(LONG *)args[OPTION_TABSIZE];
-
- if (args[OPTION_CONTINUE])
-
- options->fatal = 0;
-
- if (args[OPTION_IGNORE])
- {
- int wildcards = (options->casesensitive) ? ParsePattern((char *)args[OPTION_IGNORE], options->preparsed, sizeof(options->preparsed)) : ParsePatternNoCase((char *)args[OPTION_IGNORE], options->preparsed, sizeof(options->preparsed));
-
- if (wildcards == -1)
- {
- fprintf(stderr, "Syntax error in pattern: %s\n", (char *)args[OPTION_IGNORE]);
- }
- else
- options->ignore = (char *)args[OPTION_IGNORE];
- }
-
- if (args[OPTION_OBJECTS])
-
- options->generate_objects = 1;
-
- // generate makefile
-
- puts("# makefile for GNU make (automatically generated by makemake)");
-
- puts("# NOTE: Command lines in GNU makefiles must start with a TAB !\n");
-
- WriteString(options, "EXE =", FALSE);
-
- WriteString(options, options->exec, TRUE);
-
- WriteString(options, NULL, FALSE);
-
- WriteString(options, NULL, FALSE);
-
- // generate target "all:"
-
- if (options->generate_objects)
- {
- WriteString(options, "all : $(EXE)", FALSE);
-
- WriteString(options, NULL, FALSE);
-
- WriteString(options, NULL, FALSE);
- }
-
- for (file = (char **)args[OPTION_FILES]; *file; ++file)
- {
- // make objects (as opposed to compiling directly into executable) ?
-
- if (options->generate_objects)
- {
- char *suffix;
-
- if (strlen(*file) >= PATH_MAX)
- {
- fprintf(stderr, "Name is too long: %s\n", *file);
-
- exit(EXIT_FAILURE);
- }
-
- // examine file type
-
- strcpy(cfn, *file);
-
- if ((suffix = strrchr(cfn, '.')))
- {
- // ignore headers at this point
-
- if (stricmp(suffix, ".h"))
- {
- // source code (to be compiled) or a file to be linked with ?
-
- if (stricmp(suffix, ".c") && stricmp(suffix, ".cxx") && stricmp(suffix, ".cpp") && stricmp(suffix, ".cc") && stricmp(suffix, ".a") && stricmp(suffix, ".asm") && stricmp(suffix, ".a68k"))
- {
- // to be linked with
-
- FILE *fp;
-
- if (!(fp = fopen(cfn, "r")))
- {
- fprintf(stderr, "Can not open %s: %s\n", cfn, strerror(errno));
-
- if (options->fatal)
-
- exit(EXIT_FAILURE);
- }
- else
- fclose(fp);
-
- AddNode(options, &options->list_objects, cfn, 0);
- }
- else
- {
- // add source as first dependency
-
- AddNode(options, &options->list_localdependencies, *file, 0);
-
- // convert suffix to ".o"
-
- *suffix = 0;
-
- if (strlen(cfn) + 2 >= PATH_MAX)
- {
- fprintf(stderr, "Name is too long after adding '.o': %s\n", *file);
-
- exit(EXIT_FAILURE);
- }
-
- strcat(cfn, ".o");
-
- if (options->oprefix)
- {
- if (strlen(cfn) + strlen(options->oprefix) >= PATH_MAX)
- {
- fprintf(stderr, "Name is too long after adding object prefix: %s\n", *file);
-
- exit(EXIT_FAILURE);
- }
-
- strcpy(cpn, options->oprefix);
-
- strcat(cpn, cfn);
- }
- else
- strcpy(cpn, cfn);
-
- // object not yet generated ?
-
- if (!FindNode(options, &options->list_targets, cpn, NULL))
- {
- struct ListNode *nd = AddNode(options, &options->list_targets, cpn, 0);
-
- if (nd == NULL)
-
- exit(EXIT_FAILURE);
-
- // examine dependencies
-
- ReadSource(options, *file);
-
- // generate object file
-
- GenerateTarget(options, nd->name, GENERATE_OBJECT | GENERATE_FORCE);
-
- WriteString(options, NULL, FALSE);
-
- // update list of objects
-
- AddNode(options, &options->list_objects, nd->name, 0);
- }
- else
- {
- // add (existing) object file
-
- if (options->verbose)
-
- fprintf(stderr, "Generation of %s skipped.\n", cpn);
-
- AddNode(options, &options->list_objects, cpn, 0);
- }
-
- }
- }
- else if (options->verbose)
-
- fprintf(stderr, "File %s skipped (not a source code).\n", cpn);
- }
- else if (options->verbose)
-
- fprintf(stderr, "File %s skipped (unsupported file suffix).\n", cpn);
- }
- else
- {
- // find dependancies but do not generate objects (we will later compile directly into executable)
-
- ReadSource(options, *file);
-
- AddNode(options, &options->list_objects, *file, 0);
- }
- }
-
- // generate executable
-
- if (options->list_objects)
-
- GenerateTarget(options, NULL, GENERATE_EXEC);
-
- FreeArgs(rdArgs);
-
- if (options->verbose)
-
- fputs("Done.\n", stderr);
- }
- else
- fputs("Required arguments missing !\n", stderr);
- }
- else
- PrintFault(IoErr(), "makemake: ");
-
- free(options);
- }
- else
- fputs("Not enough memory !\n", stderr);
-
- exit(EXIT_SUCCESS);
- }
-
- ///
- /// "lists"
-
- /* -----------------------------------------------------------------------------
-
- Find 'name' in 'lst'. Return the pointer to node if it exist or NULL. If 'prec'
- is non-null, the pointer to its predecessor is stored there.
-
- */
-
- struct ListNode *
- FindNode(struct Options *options, struct ListNode **lst, const char *name, struct ListNode **prec)
- {
- register struct ListNode *node, *pred;
-
- if (!name)
-
- return(NULL);
-
- for (node = *lst, pred = (struct ListNode *)NULL; node; pred = node, node = node->succ)
- {
- if (options->casesensitive)
- {
- if (!strcmp(name, node->name))
-
- break;
- }
- else if (!stricmp(name, node->name))
-
- break;
- }
-
- if (prec)
-
- *prec = pred;
-
- return(node);
- }
-
- /* -----------------------------------------------------------------------------
-
- Add a new data <name to the list <lst>. Set <end>==1 if you want the data to be
- added at THE END of <lst>. If <x> is already in the list, the old one is
- returned. May exit if a new node can't be allocated.
-
-
- */
-
- struct ListNode *
- AddNode(struct Options *options, struct ListNode **lst, char *name, int end)
- {
- struct ListNode *new, *pred;
-
- if (!name)
-
- return(NULL);
-
- // entry already exits ?
-
- if (new = FindNode(options, lst, name, &pred))
-
- return(new);
-
- new = malloc(sizeof(struct ListNode));
-
- if (!new)
- {
- fputs("Not enough memory !\n", stderr);
-
- exit(EXIT_FAILURE);
- }
-
- /* a warning may be added if pred==NULL but, on the other hand, this is a bug and may never be. */
-
- if (end && pred)
- {
- new ->succ = NULL;
-
- pred->succ = new;
- }
- else
- {
- new->succ = *lst;
-
- *lst = new;
- }
-
- if (!(new->name = strdup(name)))
- {
- fputs("Not enough memory !\n", stderr);
-
- exit(EXIT_FAILURE);
- }
-
- return(new);
- }
-
- /* -----------------------------------------------------------------------------
-
- Free a list of objects allcated with AddNode()
-
- */
-
- void
- FreeList(struct ListNode **lst)
- {
- register struct ListNode *node, *succ;
-
- for (node = *lst; node; node = succ)
- {
- if (node->name)
-
- free(node->name);
-
- succ = node->succ;
-
- free(succ);
- }
-
- *lst = NULL;
- }
-
- ///
- /// "io"
-
- /* -----------------------------------------------------------------------------
-
- Add string <fch> to the current line. Keep track of output column (note:
- only first character of <string> is checked for TAB and only last
- character is checked for LF). Strings containing spaces are quoted if
- <smartquote> is TRUE.
-
- */
-
- void
- WriteString(struct Options *options, const char *string, int smartquote)
- {
- static int column = 0;
-
- // generate empty line if no output string is specified
-
- if (string == NULL)
- {
- puts("");
-
- column = 0;
- }
- else
- {
- int tabsize;
- int len;
- int LF;
- int separator;
-
- // does output start with TAB ?
-
- if (*string == '\t')
- {
- ++string;
-
- tabsize = (options->tab - column % options->tab);
- }
- else
- tabsize = 0;
-
- // if smart quotes are requested, add quotes if string contains spaces
-
- if (smartquote && strchr(string, ' '))
- smartquote = 2;
- else
- smartquote = 0;
-
- // output LF ?
-
- LF = FALSE;
-
- if (len = strlen(string))
- {
- if (string[len - 1] == '\n')
- {
- LF = TRUE;
-
- --len;
- }
- }
-
- // continue in new line if output would exeed margin
-
- if ((column + tabsize + len + smartquote) > options->line)
- {
- printf("\\\n");
-
- column = 0;
-
- if (tabsize)
-
- tabsize = (options->tab - column % options->tab);
- }
-
- if (tabsize)
- {
- putc('\t', stdout);
-
- column += tabsize;
- }
-
- if (smartquote)
- {
- putc('"', stdout);
-
- ++column;
- }
-
- separator = (len != 0);
-
- while (len--)
- {
- putc(*string++, stdout);
-
- ++column;
- }
-
- if (smartquote)
- {
- putc('"', stdout);
-
- ++column;
- }
-
- // start new line after output or continue in this line ?
-
- if (LF)
- {
- putc('\n', stdout);
-
- column = 0;
- }
- else if (separator)
- {
- putc(' ', stdout);
-
- ++column;
- }
- }
- }
-
- /* -----------------------------------------------------------------------------
-
- Generate next section of makefile for target <dst> (<dst> may be NULL if
- GENERATE_EXEC is set in <flags>, options->exec will be used as target in that
- case).
-
- */
-
- void
- GenerateTarget(struct Options *options, const char *dst, int flags)
- {
- // validate target
-
- if (flags & GENERATE_EXEC)
- {
- if (dst == NULL)
-
- dst = options->exec;
- }
-
- if (dst == NULL)
- {
- struct ListNode *nd;
-
- for (nd = options->list_objects; nd; nd = nd->succ)
-
- fprintf(stderr, "WARNING: No target for %s !\n", nd->name);
-
- for (nd = options->list_localdependencies; nd; nd = nd->succ)
-
- fprintf(stderr, "WARNING: No target for %s !\n", nd->name);
-
- for (nd = options->list_globaldependencies; nd; nd = nd->succ)
-
- fprintf(stderr, "WARNING: No target for %s !\n", nd->name);
-
- return;
- }
-
- // update list of targets
-
- if (dst)
- {
- if (flags & GENERATE_FORCE)
- {
- AddNode(options, &options->list_targets, (char *)dst, 0);
- }
- else if (FindNode(options, &options->list_targets, dst, NULL))
- {
- fprintf(stderr, "WARNING: %s generated twice !", dst);
-
- if (options->fatal)
-
- exit(EXIT_FAILURE);
- }
- else
- AddNode(options, &options->list_targets, (char *)dst, 0);
- }
-
- // generate next section of makefile
-
- if (flags & GENERATE_OBJECT)
- {
- // generate *.o-file from source
-
-
- struct ListNode *nd;
- char *commandline;
-
- if (options->verbose)
-
- fprintf(stderr, "Generating object %s\n", dst);
-
- WriteString(options, dst, TRUE);
-
- WriteString(options, ":", FALSE);
-
- for (nd = options->list_localdependencies; nd; nd = nd->succ)
-
- WriteString(options, nd->name, TRUE);
-
- for (nd = options->list_globaldependencies; nd; nd = nd->succ)
-
- WriteString(options, nd->name, TRUE);
-
- if (options->list_localdependencies == NULL)
- {
- fputs("Error: Can not generate object without source !\n", stderr);
-
- exit(EXIT_FAILURE);
- }
-
- WriteString(options, NULL, FALSE);
-
- // GNU make requires that commands are indented with a TAB
-
- WriteString(options, "\t", FALSE);
-
- if (commandline = ReplacePlaceholders(options, options->compile, options->list_localdependencies->name, NULL, dst, NULL))
- {
- WriteString(options, commandline, FALSE);
-
- free(commandline);
- }
-
- WriteString(options, NULL, FALSE);
- }
- else
- {
- // generate executable
-
- struct ListNode *nd;
- char *commandline;
-
- if (options->verbose)
-
- fputs("Generating executable\n", stderr);
-
- if (stricmp(dst, options->exec) == 0)
-
- dst = "$(EXE)";
-
- WriteString(options, dst, TRUE);
-
- WriteString(options, ":", FALSE);
-
- for (nd = options->list_objects; nd; nd = nd->succ)
-
- WriteString(options, nd->name, TRUE); // sources
-
- for (nd = options->list_localdependencies; nd; nd = nd->succ)
-
- WriteString(options, nd->name, TRUE); // local includes
-
- for (nd = options->list_globaldependencies; nd; nd = nd->succ)
-
- WriteString(options, nd->name, TRUE); // global includes
-
- WriteString(options, NULL, FALSE);
-
- // GNU make requires that commands are indented with a TAB
-
- WriteString(options, "\t", FALSE);
-
- if (commandline = ReplacePlaceholders(options, options->link, NULL, dst, NULL, options->list_objects))
- {
- WriteString(options, commandline, FALSE);
-
- free(commandline);
- }
-
- WriteString(options, NULL, FALSE);
-
- FreeList(&options->list_objects); // destroy source file for this target
- }
-
- // processed, all dependencies may be destroyed
-
- FreeList(&options->list_globaldependencies);
-
- FreeList(&options->list_localdependencies);
- }
-
- /* -----------------------------------------------------------------------------
-
- Look in context if the file <cfn> may or may not be processed. Current context
- <options> is "local" (<locale>==1) or "global" (<local>==0). Result: 1 (accept
- file) or 0 (ignore file).
-
- */
-
- int
- AcceptFile(struct Options *options, int local)
- {
- // ignore this file ?
-
- if (options->ignore)
- {
- int reject = (options->casesensitive) ? MatchPattern(options->preparsed, cfn) : MatchPatternNoCase(options->preparsed, cfn);
-
- if (reject)
-
- return(0);
- }
-
- if (local)
- {
- if (options->local)
-
- return(1);
- }
- else if (options->global)
- {
- return(1);
- }
- else
- return(0);
- }
-
- /* -----------------------------------------------------------------------------
-
- Look for an include file (cfn) in all paths in options->list_folders. Result: 1
- if the file can be found (the result is in cpn) or 0 if the file can not be
- found (cpn is invalid).
-
- */
-
- int
- LocateInclude(struct Options *options, int nr)
- {
- register struct ListNode *nd;
-
- int fl = strlen(cfn);
-
- for (nd = options->list_folders; nd; nd = nd->succ)
- {
- if (fl + strlen(nd->name) >= PATH_MAX)
- {
- fprintf(stderr, "Warning: path is too long (and ignored).\n'%s%s'\n", nd->name, cfn);
- }
- else
- {
- strcpy(cpn, nd->name);
-
- CompletePath(cpn);
-
- strcat(cpn, cfn);
-
- if (options->verbose)
- {
- int i;
-
- for (i = nr; i > 1; i--)
-
- fputs("-", stderr);
-
- fprintf(stderr, "-> Looking for %s", cpn);
- }
-
- if (access(cpn, 0) == 0)
- {
- if (options->verbose)
-
- fputs(" found.\n", stderr);
-
- return(1);
-
- }
- else if (options->verbose)
-
- fputs(" not found.\n", stderr);
- }
- }
-
- return(0);
- }
-
- void
- AddGlobal(struct Options *options, struct Status *status, int nr)
- {
- if (AcceptFile(options, 0))
- {
- if (LocateInclude(options, nr))
- {
- if (options->r_global)
- {
- // already processed ?
-
- if (!FindNode(options, &options->list_globaldependencies, cpn, NULL))
- {
- struct ListNode *nd = AddNode(options, &options->list_globaldependencies, cpn, 0);
-
- if (nd)
- {
- ReadSource(options,nd->name);
- }
- else
- exit(EXIT_FAILURE);
- }
- }
- else
- AddNode(options, &options->list_globaldependencies, cpn, 0);
- }
- else
- {
- fprintf(stderr, "%s (line %d): Can not locate %s !\n", cfn, status->line, cfn);
-
- if (options->fatal)
- exit(EXIT_FAILURE);
- else
- printf("# Warning: %s can not be located !\n", cfn);
- }
- }
- }
-
- void
- AddLocal(struct Options *options, struct Status *status, int nr)
- {
- if (AcceptFile(options, 1))
- {
- if (access(cfn, 0))
- {
- fprintf(stderr, "%s (line %d): Can not locate %s !\n", cfn, status->line, cfn);
-
- if (options->fatal)
- exit(EXIT_FAILURE);
- else
- printf("# Warning: %s can not be located !\n", cfn);
- }
- else
- {
- if (options->r_local)
- {
- // already processed ?
-
- if (!FindNode(options, &options->list_localdependencies, cfn, NULL))
- {
- struct ListNode *nd = AddNode(options, &options->list_localdependencies, cfn, 1);
-
- strcpy(cpn, cfn);
-
- if (nd)
- {
- ReadSource(options, nd->name);
- }
- else
- exit(EXIT_FAILURE);
- }
- }
- else
- AddNode(options, &options->list_localdependencies, cfn, 1);
- }
- }
- }
-
- /* -----------------------------------------------------------------------------
-
- Read source code
-
- */
-
- void
- ReadSource(struct Options *options, const char *file)
- {
- // # of recursion
-
- static unsigned int nbre_rec = 0;
-
- struct Status status = { 0 };
- int i;
- FILE *fp;
- char c;
- int len;
-
- if (fp = fopen(file, "r"))
- {
- if (options->verbose)
- {
- // indent according to nesting level
-
- for (i = ++nbre_rec; i > 1 && options->verbose; i--)
-
- fputs(" ", stderr);
-
- fprintf(stderr, "Reading %s\n", file);
- }
-
- status.line = 1;
-
- len = 0;
-
- while ((c = fgetc(fp)) != EOF)
- {
- if (status.ininclude)
- {
- // reading content after "#"
-
- if (status.ininclude == 9)
- {
- // reading file name after "#include <"
-
- if (len > PATH_MAX)
- {
- fputs("FATAL ERROR: FILE NAME TOO LONG !\N", stderr);
-
- exit(EXIT_FAILURE);
- }
-
- // no interpretation of the name is done as it is system dependant
-
- switch (c)
- {
- case '\n':
-
- fprintf(stderr, "%s: Unterminated #include in line %ld !\n", file, status.line);
-
- exit(EXIT_FAILURE);
-
- case '"':
-
- // it's a local include
-
- if (status.instring)
- {
- cfn[len] = 0;
-
- AddLocal(options, &status, nbre_rec);
-
- status.instring = FALSE;
- status.ininclude = FALSE;
- }
- else
- cfn[len++] = c;
-
- break;
-
- case '>':
-
- // it's a global include
-
- if (status.instring == FALSE)
- {
- cfn[len] = 0;
-
- AddGlobal(options, &status, nbre_rec);
-
- status.ininclude = FALSE;
- }
- else
- cfn[len++] = c;
-
- break;
-
- default:
-
- cfn[len++] = c;
- }
-
- if (len >= PATH_MAX)
- {
- fprintf(stderr, "%s: #include filename too long in line %ld !\n", file, status.line);
-
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- // somewhere in "#include <"
-
- switch (c) {
-
- case 'i':
-
- if (status.ininclude != 1)
-
- goto autre;
-
- ++status.ininclude;
-
- break;
-
- case 'n':
-
- if (status.ininclude != 2)
-
- goto autre;
-
- ++status.ininclude;
-
- break;
-
- case 'c':
-
- if (status.ininclude != 3)
-
- goto autre;
-
- ++status.ininclude;
-
- break;
-
- case 'l':
-
- if (status.ininclude != 4)
-
- goto autre;
-
- ++status.ininclude;
-
- break;
-
- case 'u':
-
- if (status.ininclude != 5)
-
- goto autre;
-
- ++status.ininclude;
-
- break;
- case 'd':
-
- if (status.ininclude != 6)
-
- goto autre;
-
- ++status.ininclude;
-
- break;
-
- case 'e':
-
- if (status.ininclude != 7)
-
- goto autre;
-
- ++status.ininclude;
-
- break;
-
- case '\t':
- case ' ':
-
- if ((status.ininclude != 8) && (status.ininclude != 1))
-
- goto autre;
-
- break;
-
- case '<':
-
- if (status.ininclude != 8)
-
- goto autre;
-
- ++status.ininclude;
-
- len = 0;
-
- break;
-
- case '"':
-
- if (status.ininclude != 8)
-
- goto autre;
-
- ++status.ininclude;
-
- status.instring = 1;
-
- len = 0;
-
- break;
-
- default :
-
- goto autre;
- }
- }
- }
- else if (status.instring || status.inconstant)
- {
- // reading a string or string constant
-
- switch (c)
- {
- case '\n':
-
- fprintf(stderr, "%s: Unterminated string in line %ld !\n", file, status.line);
-
- exit(EXIT_FAILURE);
-
- case '\\':
-
- // ignore next character (unless preced by \)
-
- if (status.ignore)
- status.ignore = 0;
- else
- status.ignore = 1;
-
- break;
-
- case '"':
-
- if (status.instring && !status.ignore)
- status.instring = 0;
- else
- status.ignore = 0;
-
- break;
-
- case '\'':
-
- if (status.inconstant && !status.ignore)
- status.inconstant = 0;
- else
- status.ignore = 0;
-
- break;
-
- default:
-
- status.ignore = 0;
- }
- }
- else if (status.incommentcpp)
- {
- // reading a C++ comment
-
- if (c == '\n')
- {
- status.incommentcpp = 0;
-
- ++status.line;
- }
- }
- else if (status.incomment)
- {
- // reading a C comment
-
- if (c == '\n')
- {
- ++status.line;
-
- status.star = 0;
-
- }
- else if (c == '*')
- {
- // nesting ?
-
- if (status.slash)
- {
- status.slash = 0;
-
- if (options->nestedcomments == FALSE)
- {
- fprintf(stderr, "%s: Nested comments not allowed (line %ld) !\n", file, status.line);
-
- exit(EXIT_FAILURE);
- }
- else
- ++status.incomment;
-
- status.star = 0;
- }
- else
- status.star = 1;
- }
- else if (c == '/')
- {
- if (status.star)
- {
- status.star = 0;
- status.slash = 0;
-
- --status.incomment;
- }
- else
- status.slash = 1;
- }
- else
- {
- status.star = 0;
- status.slash = 0;
- }
- }
- else if (status.ignore)
- {
- status.ignore = 0;
-
- if (c == '\n')
-
- ++status.line;
- }
- else
- {
- // plain source code
-
- autre:
-
- status.ininclude = 0;
-
- switch (c) {
-
- case '/':
-
- // a c++ comment ?
-
- if (status.slash)
- {
- status.slash = 0;
- status.incommentcpp = 1;
- }
- else if (status.star)
- {
- fprintf(stderr, "%s: Unexpected */ in line %ld !\n", file, status.line);
-
- exit(EXIT_FAILURE);
- }
- else
- status.slash = 1;
-
- break;
-
- case '*':
-
- // opening new comment ?
-
- if (status.slash)
- {
- status.slash = 0;
-
- if ((++status.incomment > 1) && (options->nestedcomments == FALSE))
- {
- fprintf(stderr, "%s: Nested comments not allowed (line %ld) !\n", file, status.line);
-
- exit(EXIT_FAILURE);
- }
- }
- else
- status.star = 1;
-
- break;
-
- case '\n':
-
- ++status.line;
-
- status.star = 0;
- status.slash = 0;
-
- break;
-
- case '\\':
-
- status.ignore = 1;
- status.star = 0;
- status.slash = 0;
-
- break;
-
- case '\'':
-
- status.inconstant = 1;
- status.star = 0;
- status.slash = 0;
-
- break;
-
- case '"':
-
- status.instring = 1;
- status.star = 0;
- status.slash = 0;
-
- break;
-
- case '{':
-
- ++status.inblock;
-
- status.star = 0 ;
- status.slash = 0;
-
- break;
-
- case '}':
-
- if (!status.inblock)
- {
- fprintf(stderr, "%s: Unexpected } in line %d\n", file, status.line);
-
- exit(EXIT_FAILURE);
-
- }
- else
- --status.inblock;
-
- status.star = 0 ;
- status.slash = 0;
-
- break;
-
- case '#':
-
- status.star = 0;
- status.slash = 0;
- status.ininclude = 1;
-
- break;
-
- default:
-
- status.star = 0;
- status.slash = 0;
- status.ininclude = 0;
- }
- }
- }
-
- fclose(fp);
-
- --nbre_rec;
-
- if (status.inblock)
- {
- fprintf(stderr, "%s: %ld pending block(s) !\n", file, status.inblock);
-
- if (options->fatal)
-
- exit(EXIT_FAILURE);
- }
-
- if (status.incomment)
- {
- fprintf(stderr, "%s : %ld pending C comment(s) !\n", file, status.incomment);
-
- if (options->fatal)
-
- exit(EXIT_FAILURE);
- }
-
- if (status.instring || status.inconstant)
- {
- fprintf(stderr, "%s: Unterminated string(s)", file);
-
- if (options->fatal)
-
- exit(EXIT_FAILURE);
- }
-
- if (status.ininclude == 9)
- {
- fprintf(stderr, "%s : Unexpected end of file when reading #include directive !\n", file);
-
- if (options->fatal)
-
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- fprintf(stderr, "Can not open %s: %s\n", file, strerror(errno));
-
- if (options->fatal)
-
- exit(EXIT_FAILURE);
- }
- }
-
- /* -----------------------------------------------------------------------------
-
- Like strcmp() but considers length of <x> only. Stores pointer to first
- character of <y> which is not in 'x' in <end> if strings match up to the length
- of <x>. function succeeds).
-
- */
-
- int
- strcmpopt(const char *y, const char *x, const char **end)
- {
- for (; *x; x++, y++)
-
- if (*x != *y)
-
- return(*x - *y);
-
- if (end)
-
- *end = y;
-
- return(0);
- }
-
- /* -----------------------------------------------------------------------------
-
- Some systems (like AmigaDOS) use ':' as special separator in filename (i.e.
- after drivename). This may confuse 'make' so we display a warning.
-
- */
-
- void
- ValidateFilename(const char *file)
- {
- if (strchr(file, ':'))
-
- fprintf(stderr, "Warning: ':' in file names may confuse make (%s) !\n", file);
- }
-
- /* ------------------------------- CompletePath --------------------------------
-
- Add trailing "/" to path (unless already terminated by "/" or ":")
-
- */
-
- void
- CompletePath(char *path)
- {
- if (*path)
- {
- path = strchr(path, 0) - 1;
- }
-
- if ((*path != '/') && (*path != ':'))
-
- strcat(path, "/");
- }
-
- ///
- /// "strings"
-
- /* ---------------------------- ReplacePlaceholders ----------------------------
-
- Replace placeholders (%exe, %src, %obj, %objs) in <string>
- */
-
- char *
- ReplacePlaceholders(struct Options *options, const char *string, const char *src, const char *exe, const char *obj, const struct ListNode *objs)
- {
- char *buffer;
- int len;
-
- if (len = strlen(string))
- {
- int freebuffer;
- int buffersize;
-
- freebuffer = 512;
- buffersize = 512 + (++len);
-
- // duplicate string
-
- if (buffer = (char *)malloc(buffersize))
- {
- char *placeholder;
-
- strcpy(buffer, string);
-
- do
- {
- struct ListNode *replacements;
- char *replacement;
- int placeholdersize;
-
- replacements = NULL;
- replacement = NULL;
-
- // locate next placeholder
-
- placeholdersize = 4;
-
- if (placeholder = strstr(buffer, "%objs"))
- {
- replacements = (struct ListNode *)objs;
-
- placeholdersize = 5;
- }
- else if (placeholder = strstr(buffer, "%exe"))
- {
- replacement = (char *)exe;
- }
- else if (placeholder = strstr(buffer, "%src"))
- {
- replacement = (char *)src;
- }
- else if (placeholder = strstr(buffer, "%obj"))
-
- replacement = (char *)obj;
-
- if (placeholder)
- {
- // remove placeholder
-
- memmove(placeholder, placeholder + placeholdersize, buffersize - freebuffer - (placeholder - buffer) - placeholdersize);
-
- freebuffer += placeholdersize;
-
- if (replacement || replacements)
- {
- int count = 0;
-
- // insert replacement(s)
-
- do
- {
- if (replacements)
-
- replacement = replacements->name;
-
- if (replacement)
- {
- int replacementsize;
- int space;
-
- replacementsize = strlen(replacement);
-
- // add separator before 2nd, 3rd, ... entry
-
- space = (++count == 1) ? 0 : 1;
-
- // enlarge buffer as needed
-
- if (freebuffer < (replacementsize + space))
- {
- if (buffer = (char *)realloc(buffer, buffersize + PATH_MAX))
- {
- freebuffer += PATH_MAX;
- buffersize += PATH_MAX;
- }
- else
- break;
- }
-
- // make room
-
- memmove(placeholder + replacementsize + space, placeholder, buffersize - freebuffer - (placeholder - buffer));
-
- // insert replacement
-
- memmove(placeholder, replacement, replacementsize);
-
- freebuffer -= replacementsize;
- freebuffer -= space;
-
- while (space--)
-
- placeholder[replacementsize + space] = 32;
- }
-
- if (replacements)
-
- replacements = replacements->succ;
-
- } while (replacements);
- }
- }
-
- } while (placeholder);
- }
- }
- else
- buffer = NULL;
-
- return(buffer);
- }
-
- ///
-